package it.polimi.swKnights.SWIMv2.ejb.searchEngine;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;

public abstract class SimpleSearch extends Search
{

	protected abstract String getQueryTextEqual(String attribute);

	protected abstract String getQueryTextLike(String attribute);

	protected abstract void tryUserAttribute(String attribute,
			boolean hasToBeEqual, String value,
			List<UserQueryResult> listQueryRes, Integer ranking, String userName);

	protected abstract void tryAbilityAttribute(boolean hasToBeEqual,
			String ability_name, List<UserQueryResult> listQueryRes,
			Integer ranking, String userName);

	protected abstract void tryNameAndSurname(String name, String surname,
			List<UserQueryResult> listQueryRes, Integer ranking, String userName);

	protected void trySurnameEqual(String user1,
			List<UserQueryResult> listQueryRes, int ranking, String userName)
	{
		this.tryUserAttribute("surname", true, user1, listQueryRes, ranking, userName);

	}

	protected void tryNameEqual(String user1,
			List<UserQueryResult> listQueryRes, int ranking, String userName)
	{
		this.tryUserAttribute("name", true, user1, listQueryRes, ranking, userName);

	}

	/**
	 * e.g. tizio LIKE ooOOOOootizio_90_megatra!
	 * 
	 * @param user
	 * @param listQueryRes
	 * @param ranking
	 */
	protected void tryUsernameLike(String user,
			List<UserQueryResult> listQueryRes, int ranking, String userName)
	{
		this.tryUserAttribute("userName", false, user, listQueryRes, ranking, userName);
	}

	/**
	 * Update the passed list with found user with passed ranking
	 * 
	 * @param ranking
	 */
	protected void tryUsernameEqual(String user1,
			List<UserQueryResult> listQueryRes, int ranking, String userName)
	{
		this.tryUserAttribute("userName", true, user1, listQueryRes, ranking, userName);
	}

	protected void tryAbilityEqual(String ability,
			List<UserQueryResult> listQueryRes, Integer ranking, String userName)
	{
		this.tryAbilityAttribute(true, ability, listQueryRes, ranking, userName);

	}

	protected List<UserQueryResult> getListOfResultFromOneStringQuery(String s1, String userName)
	{
		// 1 parameters search
		List<UserQueryResult> listQueryRes = new ArrayList<UserQueryResult>();
		// forse una treelist meglio asintoticamente, ma con liste piccole..

		String user1 = s1;

		// query if name is equal to any of the table in the DB
		this.tryUsernameEqual(user1, listQueryRes, 100, userName);

		// query if the username is contained in any of the table in the DB
		this.tryUsernameLike(user1, listQueryRes, 75, userName);

		String ability1 = s1;

		// find all users with s1 as ability
		this.tryAbilityEqual(ability1, listQueryRes, 70, userName);

		String surname = s1;
		this.trySurnameEqual(surname, listQueryRes, 50, userName);

		String name = s1;
		this.tryNameEqual(name, listQueryRes, 40, userName);

		/*
		 * DON'T KNOW HOW CAUSE JOIN IS EJB-JOIN this.tryAbilityLike(ability1,
		 * listQueryRes, 40);
		 */

		Collections.sort(listQueryRes);
		return listQueryRes;

	}

	protected List<UserQueryResult> getListOfResultFromTwoStringsQuery(
			String s1, String s2, String userName)
	{

		// 2 parameters search
		List<UserQueryResult> listQueryRes = new ArrayList<UserQueryResult>();
		String user1 = s1;
		String user2 = s2;

		this.tryNameAndSurname(s1, s2, listQueryRes, 90, userName);
		this.tryNameAndSurname(s2, s1, listQueryRes, 90, userName);

		// query if name is equal to any of the table in the DB
		this.tryUsernameEqual(user1, listQueryRes, 80, userName);
		this.tryUsernameEqual(user2, listQueryRes, 80, userName);

		// query if the username is contained in any of the table in the DB
		this.tryUsernameLike(user1, listQueryRes, 75, userName);
		this.tryUsernameLike(user2, listQueryRes, 75, userName);

		String ability1 = s1;
		String ability2 = s2;

		// find all users with s1 as ability
		this.tryAbilityEqual(ability1, listQueryRes, 70, userName);
		this.tryAbilityEqual(ability2, listQueryRes, 70, userName);

		/*
		 * DON'T KNOW HOW CAUSE JOIN IS EJB-JOIN this.tryAbilityLike(ability1,
		 * listQueryRes, 40); this.tryAbilityLike(ability2, listQueryRes, 40);
		 */

		Collections.sort(listQueryRes);
		return listQueryRes;

	}

	/**
	 * split the query string to see how words compose it. then try to do smart
	 * queries, combining parameters of Registered User the method does not
	 * check all the possible combination to keep its execution time polynomial
	 * 
	 * @param query
	 * @return
	 */
	protected List<Map<String, String>> getListOfMapFromGeneralQuery(
			String query, String userName)
	{
		query = removeUselessWords(query);

		if (query.length() == 0)
		{
			throw new IllegalArgumentException("empty query passed");
		}

		List<UserQueryResult> listQR = null;
		List<UserQueryResult> listQrAllCouples = new ArrayList<UserQueryResult>();

		String full_query = query;
		String[] S_BIG = full_query.split(" ");
		int first = 0, second = 1;

		// (A) length = 3
		// (B) 0 1 2
		// (C) "car" "map" "boat"
		// (D) 0 1
		// (E) 1 2
		// (F) 1 2 NO!

		while (first < S_BIG.length && second < 5)
		{
			if (second < S_BIG.length)
			{
				query = S_BIG[first] + " " + S_BIG[second];
			}
			else
			{
				query = S_BIG[first];
			}

			if (first == S_BIG.length - 2)
			{
				first++; // see row (F)
			}

			first++;
			second++;

			// data una query (string) di al + due parole separate da spazio
			// ricava una lista di uqr

			// check query to see how many words is it
			String[] S = query.split(" ");

			String s1 = "";
			String s2 = "";
			if (S.length == 1)
			{
				s1 = S[0];
			}
			else if (S.length == 2)
			{
				s1 = S[0];
				s2 = S[1];
			}
			else if (S.length >= 3)
			{
				throw new IllegalArgumentException(
						"too many arguements, we make query only on 2 arguments");
			}

			// call the method to let him handle wether query on one or 2
			// strings
			// depending on the emptiness on one of them

			// check input data, for empty strings
			if (s1.length() == 0 && s1.length() == s2.length())
			{
				throw new IllegalArgumentException();
			}

			// if a string is empty, it become s2, by construction
			if (s1.length() == 0)
			{
				s1 = s2;
				s2 = "";
			}

			// if just one string is set, we'll give more importance to ability
			if (s2.length() == 0)
			{
				listQR = getListOfResultFromOneStringQuery(s1, userName);
			}
			else
			// if 2 string, we'll give more importance to name and surname
			{
				listQR = getListOfResultFromTwoStringsQuery(s1, s2, userName);
			}

			this.removeSameUserDifferentRanking(listQR);

			// qui ho la lista di uqr data dalla query di 2 parole
			listQrAllCouples.addAll(listQR);

		}

		this.removeSameUserDifferentRanking(listQR);

		return this.createListOfMap(listQR);

	}
}
